/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use log::{error, info};
use actix_web::web::{Json, Query};
use actix_web::{HttpRequest, HttpResponse};
use endorserment::services::cert_service::CertService;
use jwt::jwt_parser::JwtParser;
use serde::Serialize;
use serde_json::Value;
use validator::Validate;
use key_management::api::{CryptoOperations, DefaultCryptoImpl, SignResponse};
use crate::entities::db_model::rv_db_model::ActiveModel;
use crate::entities::inner_model::rv_content::RefValueDetails;
use crate::entities::inner_model::rv_model::RefValueModel;
use crate::error::ref_value_error::RefValueError;
use crate::entities::request_body::validator::Validator;
use crate::error::ref_value_error::RefValueError::{InvalidParameter, JsonParseError, VerifyError};
use config_manager::types::CONFIG;

pub struct Utils {}

impl Utils {
    /// Parses reference value details from JWT content
    ///
    /// # Arguments
    /// * `content` - JWT formatted content string
    ///
    /// # Returns
    /// * `Ok(RefValueDetails)` - Successfully parsed reference value details
    ///
    /// # Errors
    /// Returns `RefValueError` when:
    /// * JWT parsing fails
    /// * JSON parsing fails
    pub fn parse_rv_detail_from_jwt_content(content: &str) -> Result<RefValueDetails, RefValueError> {
        let payload = JwtParser::get_payload(content).map_err(|e| InvalidParameter(e.to_string()))?;
        serde_json::from_str::<RefValueDetails>(&payload).map_err(|e| JsonParseError(e.to_string()))
    }

    /// Checks if signature is required
    ///
    /// # Returns
    /// * `Ok(bool)` - Whether signature is required
    ///
    /// # Errors
    /// Returns `RefValueError` when:
    /// * Failed to get config instance
    pub fn is_require_sign() -> Result<bool, RefValueError> {
        match CONFIG.get_instance() {
            Ok(config) => Ok(config.attestation_service.key_management.is_require_sign),
            Err(e) => {
                let error_msg = format!("Failed to get config instance: {}", e);
                error!("{}", error_msg);
                Err(RefValueError::InvalidParameter(error_msg))
            }
        }
    }

    /// Signs a reference value model
    ///
    /// # Arguments
    /// * `model` - Reference value model to be signed
    ///
    /// # Returns
    /// * `Ok((Vec<u8>, String))` - Signature and key version
    ///
    /// # Errors
    /// Returns `RefValueError` when:
    /// * Signing operation fails
    pub async fn sign_by_ref_value_model(model: &RefValueModel) -> Result<(Vec<u8>, String), RefValueError> {
        let mut bytes = Vec::new();
        bytes.extend_from_slice(model.id.as_bytes());
        bytes.extend_from_slice(model.uid.as_bytes());
        bytes.extend_from_slice(model.name.as_bytes());
        bytes.extend_from_slice(model.attester_type.as_bytes());
        bytes.extend_from_slice(model.content.as_bytes());
        match DefaultCryptoImpl.sign(&bytes, "FSK").await {
            Ok(SignResponse {signature, key_version}) => {
                info!("Signed the ref_value model successfully");
                Ok((signature, key_version))
            }
            Err(e) => {
                error!("Sign failed: {}", e);
                Err(RefValueError::SignatureError(e.to_string()))
            }
        }
    }

    /// Signs a database reference value model
    ///
    /// # Arguments
    /// * `model` - Database reference value model to be signed
    ///
    /// # Returns
    /// * `Ok((Vec<u8>, String))` - Signature and key version
    ///
    /// # Errors
    /// Returns `RefValueError` when:
    /// * Model encoding fails
    /// * Signing operation fails
    pub async fn sign_by_ref_value_db_model(model: ActiveModel) -> Result<(Vec<u8>, String), RefValueError> {
        let bytes = Self::encode_rv_db_model_to_bytes(model)?;
        match DefaultCryptoImpl.sign(&bytes, "FSK").await {
            Ok(SignResponse {signature, key_version}) => {
                info!("Signed the ref_value db model successfully");
                Ok((signature, key_version))
            }
            Err(e) => {
                error!("Sign failed: {}", e);
                Err(RefValueError::SignatureError(e.to_string()))
            }
        }
    }
    
    /// Encodes a database reference value model into a byte sequence
    ///
    /// # Arguments
    /// * `model` - Database reference value model to be encoded
    ///
    /// # Returns
    /// * `Ok(Vec<u8>)` - Encoded byte sequence
    ///
    /// # Errors
    /// Returns `RefValueError` when:
    /// * Model is missing required fields (id, uid, name, attester_type, content)
    pub fn encode_rv_db_model_to_bytes(model: ActiveModel) -> Result<Vec<u8>, RefValueError> {
        let mut bytes = Vec::new();
        if None == model.id.clone().into_value() {
            error!("Model does not have an id, sign failed");
            return Err(RefValueError::SignatureError("Model does not have an id, sign failed".to_string()));
        }
        bytes.extend_from_slice(model.id.unwrap().as_bytes());
        if None == model.uid.clone().into_value() {
            error!("Model does not have an uid, sign failed");
            return Err(RefValueError::SignatureError("Model does not have an uid, sign failed".to_string()));
        }
        bytes.extend_from_slice(model.uid.unwrap().as_bytes());
        if None == model.name.clone().into_value() {
            error!("Model does not have a name, sign failed");
            return Err(RefValueError::SignatureError("Model does not have a name, sign failed".to_string()));
        }
        bytes.extend_from_slice(model.name.unwrap().as_bytes());
        if None == model.attester_type.clone().into_value() {
            error!("Model does not have a attester_type, sign failed");
            return Err(RefValueError::SignatureError("Model does not have a attester_type, sign failed".to_string()));
        }
        bytes.extend_from_slice(model.attester_type.unwrap().as_bytes());
        if None == model.content.clone().into_value() {
            error!("Model does not have a content, sign failed");
            return Err(RefValueError::SignatureError("Model does not have a content, sign failed".to_string()));
        }
        bytes.extend_from_slice(model.content.unwrap().as_bytes());
        Ok(bytes)
    }

    /// Extracts user ID from HTTP request headers
pub fn extract_user_id(req: &HttpRequest) -> Result<String, RefValueError> {
    req.headers()
        .get("User-Id")
        .and_then(|id| id.to_str().ok())
        .map(|s| s.to_string())
        .ok_or(InvalidParameter("Missing User-Id header".to_string()))
}

/// Parses JSON request body and validates it
pub fn parse_and_validate<T: Validate + for<'de> serde::Deserialize<'de>>(
    req_body: Json<Value>,
) -> Result<T, RefValueError> {
    let body: T = serde_json::from_value(req_body.into_inner())
        .map_err(|e| JsonParseError(e.to_string()))?;
    body.validate()
        .map_err(|e| InvalidParameter(e.to_string()))?;
    Ok(body)
}

/// Verifies content signature using certificate service
pub async fn verify_by_cert(user_id: &str, content: &str) -> Result<(), RefValueError> {
    let alg = JwtParser::get_alg(content).map_err(|e| InvalidParameter(e.to_string()))?;
    let signature = JwtParser::get_signature(content).map_err(|e| InvalidParameter(e.to_string()))?;
    let base_data = JwtParser::get_base_data(content);

    let verify_res = match CertService::verify_by_cert(
        "refvalue",
        &user_id,
        &signature,
        alg,
        &base_data.as_bytes()
    ).await {
        Ok(verify_res) => verify_res,
        Err(e) => {
            error!("reference value verify failed: {:?}", e);
            return Err(VerifyError(e.to_string()));
        }
    };

    if !verify_res {
        return Err(VerifyError("Failed to verify reference value signature".to_string()));
    }
    Ok(())
}

/// Handles HTTP response formatting for query results
pub fn handle_response<T: Serialize>(res: Result<Vec<T>, RefValueError>) -> Result<HttpResponse, RefValueError> {
    match res {
        Ok(query_res) => {
            let mut response = serde_json::Map::new();
            response.insert(
                "ref_values".to_string(),
                serde_json::to_string(&query_res).unwrap().parse()?
            );
            Ok(HttpResponse::Ok().json(response))
        }
        Err(e) => {
            error!("Failed to query Reference Value: {:?}", e.to_string());
            Err(e)
        }
    }
}

/// Extracts and validates IDs parameter from query string
pub fn extract_ids_param(query_params: &Query<Value>) -> Result<Option<Vec<String>>, RefValueError> {
    if let Some(ids_value) = query_params.get("ids") {
        let ids_str = ids_value
            .as_str()
            .ok_or(InvalidParameter("ids parameter must be a string".to_string()))?;

        let ids = ids_str
            .split(',')
            .map(str::trim)
            .filter(|s| !s.is_empty())
            .map(String::from)
            .collect::<Vec<_>>();

        Validator::validate_ids_could_none(&Some(ids.clone()))
            .map_err(|e| InvalidParameter(e.to_string()))?;

        Ok(Some(ids))
    } else {
        Ok(None)
    }
}

/// Extracts and validates attester_type parameter from query string
pub fn extract_attester_type(query_params: &Query<Value>) -> Result<Option<&str>, RefValueError> {
    if let Some(attester_type_value) = query_params.get("attester_type") {
        let attester_type = attester_type_value
            .as_str()
            .ok_or(InvalidParameter("attester_type parameter must be a string".to_string()))?;

        Validator::validate_attester_type_could_none(&Some(attester_type.to_string()))
            .map_err(|e| InvalidParameter(e.to_string()))?;

        Ok(Some(attester_type))
    } else {
        Ok(None)
    }
}
}